package core

import (
	"fmt"
	"math/rand"
)

// dbg var used = make(map[rune]int, 1000)
// dbg
func prtC(c Class_t) {
	for i := 0; i < len(c.Data); i++ {
		for j := 0; j < len(c.Data[i]); j++ {
			fmt.Print(c.Data[i][j].Name, " | ")

		}
		fmt.Println()
	}
}

// 新建教室
func NewClass(i, j int) Class_t {
	class := Class_t{
		Data: make([][]Student_t, i),
		//Bests: make([]string, 0),
		//Len:   i * j,
	}
	for k := range class.Data {
		class.Data[k] = make([]Student_t, j)
	}
	return class
}

// 随机排列教室
// 警告!!!非线程安全
func (class *Class_t) Rand() {
	//循环n次,每次随机挑4个坐标交换
	n := rand.Intn(100) + 10
	lenX, lenY := len(class.Data), len(class.Data[0])
	for range n {
		x1, y1 := rand.Intn(lenX), rand.Intn(lenY)
		x2, y2 := rand.Intn(lenX), rand.Intn(lenY)
		class.Swap(x1, y1, x2, y2)
	}
}

// 不深不浅的拷贝
// 警告!!!如果要修改学生的属性,不能用这个方法进行深拷贝
func (class *Class_t) Copy() Class_t {
	newClass := NewClass(len(class.Data), len(class.Data[0]))

	//现在newClass和class长度一样
	for i, j := 0, 0; i != -1; i, j = class.Range(i, j) {
		newClass.Data[i][j] = class.Data[i][j]
	}

	return newClass
}

// 交换在(i1,j1),(i2,j2)处的学生
func (class *Class_t) Swap(i1, j1, i2, j2 int) {
	class.Data[i1][j1], class.Data[i2][j2] = class.Data[i2][j2], class.Data[i1][j1]
}

//判断两个class相等_已废弃
/*func (class1 Class_t) EqualTo(class2 Class_t) bool {
	if len(class1.Data) != len(class2.Data) {
		return false
	}

	for i := range class1.Data {
		if len(class1.Data[i]) != len(class2.Data[i]) {
			return false
		}
		for j := range class1.Data[i] {
			if class1.Data[i][j].Name != class2.Data[i][j].Name {
				return false
			}
		}
	}

	return true
}*/

// 获取完整的class的索引,用于for循环遍历
func (class *Class_t) Range(i, j int) (int, int) {
	if j < len(class.Data[i])-1 { //这列没有遍历完
		return i, j + 1
	}
	/*else*/ if i < len(class.Data)-1 { //这列遍历完,但整个教室没有遍历完
		return i + 1, 0
	}
	/*else*/ return -1, -1
}

// 获取教室的噪声
func (class *Class_t) GetNoise() float64 {
	var (
		noise float64
		i, j  int //后面addNoise要用
	)
	addNoise := func(surrI, surrJ int) {
		if surrI != -1 {
			noise += class.Data[i][j].Noise * class.Data[surrI][surrJ].Noise
		}
	}
	for i, j = 0, 0; i != -1; i, j = class.Range(i, j) {
		//计算讲话噪音
		addNoise(class.up(i, j))
		addNoise(class.lu(i, j))
		addNoise(class.lt(i, j))
		addNoise(class.ld(i, j))

		//计算身高噪音
		if dnI, dnJ := class.dn(i, j); dnI != -1 {
			noise += class.Data[i][j].Height - class.Data[dnI][dnJ].Height
		}
	}
	//fmt.Println(used)
	return noise
}

/*古老的获取教室id_已废弃
func (class Class_t) GetID() string {
	//康托展开写不来了,现在打算就把教室每个学生的id拼接起来
	var id string
	for i, j := 0, 0; i != -1; i, j = class.Range(i, j) {
		if class.Data[i][j].ID == "" { //不坐人
			id += "-1"
		}
		id += class.Data[i][j].ID
	}
	return id
}
*/

/*古老的从id还原教室_已废弃
func (class Class_t) ResetClassFromID(id string) {
	findIDOwner := func(id string) Student_t {
		for i, j := 0, 0; i != -1; i, j = class.Range(i, j) {
			if class.Data[i][j].ID == id {
				return class.Data[i][j]
			}
		}
		panic("找不到对应的id")
	}

	class2 := NewClass(len(class.Data), len(class.Data[0]))
	var i2, j2 int
	for i := 0; i < len(id)-2 && i2 < len(class.Data) && j2 < len(class.Data[0]); i += 2 {
		class2.Data[i2][j2] = findIDOwner(id[i : i+2])

		i2, j2 = class2.Range(i2, j2)
	}
	prtC(class2) //TODO:最后一个没有放进去

	class.Data = class2.Data
}
*/

//-----------------------------------------------------------------------------------------------------

// 返回8个方位(上下左右,左上左下右上右下)的学生的坐标
func (class *Class_t) up(i, j int) (int, int) { //上
	if j-1 < 0 {
		return -1, -1
	}
	return i, j - 1
}
func (class *Class_t) dn(i, j int) (int, int) { //下
	if j+1 >= len(class.Data[i]) {
		return -1, -1
	}
	return i, j + 1
}
func (class *Class_t) lt(i, j int) (int, int) { //左
	if i-1 < 0 { //教室要换座位,因此要保证换完座位后也是安静的
		return len(class.Data) - 1, j
	}
	return i - 1, j
}
func (class *Class_t) rt(i, j int) (int, int) { //右
	if i+1 >= len(class.Data) {
		return 0, j
	}
	return i + 1, j
}
func (class *Class_t) lu(i, j int) (int, int) { //左上
	//警告!不可以先处理上下! 处理上下时可能返回(-1,-1)
	i, j = class.lt(i, j)
	return class.up(i, j)
}
func (class *Class_t) ld(i, j int) (int, int) { //左下
	i, j = class.lt(i, j)
	return class.dn(i, j)
}
func (class *Class_t) ru(i, j int) (int, int) { //右上
	i, j = class.rt(i, j)
	return class.up(i, j)
}
func (class *Class_t) rd(i, j int) (int, int) { //右下
	i, j = class.rt(i, j)
	return class.dn(i, j)
}
